// bdlb_scopeexit.h                                                   -*-C++-*-
#ifndef INCLUDED_BDLB_SCOPEEXIT
#define INCLUDED_BDLB_SCOPEEXIT

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a general-purpose proctor object for scope-exit logic.
//
//@CLASSES:
//  bdlb::ScopeExit: executes a function upon destruction
//  bdlb::ScopeExitAny: an alias to `ScopeExit<bsl::function<void()>>`
//  bdlb::ScopeExitUtil: C++11 or later factory method for creating guards
//
//@MACROS:
//  BDLB_SCOPEEXIT_GUARD: creates a scope guard using an exit function
//  BDLB_SCOPEEXIT_PROCTOR: creates a scope proctor from name and exit function
//
//@SEE_ALSO:
// P0052R6 - Generic Scope Guard and RAII Wrapper for the Standard Library
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0052r6.pdf
//
//@DESCRIPTION:
// This component provides a class template mechanism `bdlb::ScopeExit`, that
// will invoke a client supplied function upon its destruction.
// `bdlb::ScopeExit` is intended to facilitate creating scoped-proctors
// (similar to those found in {`bslma`}) that run a user-specified exit
// function upon their destruction, unless `release()`-d.  The primary purpose
// of such a proctor is to execute a guaranteed undo of some operation in case
// the complete chain of operations was not successful (exception thrown or
// early return).  The proctor may also be used as a guard to unconditionally
// run its exit function upon exiting a scope, however for such guards
// dedicated classes are highly recommended (see also {Guard vs Proctor}.  In
// case of a sufficiently functional C++11 or later platform this component
// also defines a utility `bdlb::ScopeExitUtil` containing a factory method for
// creating `bdlb::ScopeExit` objects (`makeScopeExit`).  This component also
// defines a type alias `bdlb::ScopeExitAny` that is used in C++03 code to
// create a proctor where the type of the exit function is not known (for
// example it is the result of a bind expression).  Finally, this component
// defines two macros that allow creating the `bdlb::ScopeExit` objects,
// without mentioning the exit function type, in a uniform way for platforms
// limited to C++03 and those supporting sufficiently functional C++11 or
// later, but with a more efficient implementation for the latter.  The first
// macro, `BDLB_SCOPEEXIT_PROCTOR` creates a scope proctor with a given
// variable name and exit function.  The second macro, `BDLB_SCOPEEXIT_GUARD`
// creates a scope guard variable of unspecified name given only an exit
// function argument.  See also {Guard vs Proctor}, and {C++03 Restrictions
// When Exit Function Type is Unknown}.
//
///Guard vs Proctor
///----------------
// Guard and Proctor are terminology used by BDE methodology (see below).
// Because `bdlb::ScopeExit` is so general (its exit function is provided by
// the user) it can be used both as a Guard and as a Proctor.  Below are the
// BDE definitions followed by an explanation of how they apply to this
// component.
//
///Definitions
///- - - - - -
// A (scoped) Guard is an object that maintains control over an associated
// resource (often acquired on construction) and releases that control when the
// Guard is destroyed (typically at scope exit -- either normally or because an
// exception was thrown).  The guard may provide an explicit release method,
// but -- unlike a Proctor -- such a release method is not commonly used.
//
// A Proctor is a special kind of guard intended to restore a valid state under
// abnormal circumstances (e.g., a thrown exception), until a valid state is
// restored normally, after which the Proctor's responsibility is explicitly
// released by its client.  The Proctor must provide a mechanism to release the
// resource from management, and -- unlike a standard Guard -- its management
// responsibility is typically released prior to its destruction.
//
///Further Explanation
///- - - - - - - - - -
// A Guard controls the lifetime a resource, it owns it during the resource's
// complete lifetime, and its purpose is to free up that resource once the work
// that needed it is done.  Guards may provide a `release` method for "off
// label use" in case the responsibility for freeing up the resource is
// transferred to some other code, but it is not its common use.
//
// A Proctor is commonly responsible for undoing changes when a locally
// non-recoverable error occurs.  Proctors do not necessarily clean up
// resources (although they might, as part of restoring a valid state).  When
// all goes well, Proctors do nothing, because when all the work is
// successfully completed the user code "deactivates" the Proctor (or Proctors)
// to "commit" the work by calling the `release` method.
//
///C++03 Restrictions When Exit Function Type Is Unknown
///-----------------------------------------------------
// There are two restrictions when using this component with C++03 and both
// are related to missing core language features.
//
// The first restriction is related to `bdlb::ScopeExit` being a move-only
// type, and although this class tries its best to emulate move semantics,
// returning an instance of `bdlb::ScopeExit` from a factory function is just
// not feasible under C++03.  It is technically possible, but would require a
// lot of boilerplate code on the user side, making the use of the component
// way too cumbersome to use under C++03.
//
// The second restriction is caused by the absence of the type-deducing `auto`
// keyword in C++03.  Although we can deduce the type of the exit function in
// the factory method, without the type deduction capabilities provided by
// `auto` we cannot turn that return type into the type of a variable.
//
// For the above reasons we do not generate or use a factory method in C++03
// but rely on `bsl::function<void()>` (as described below) to define a type
// that is able to store and call any exit function.
//
// In case the type of the exit function is known to the programmer (see
// {Example 2: Using a Scope Exit Guard In C++03}) it is possible to simply
// provide that type as the template argument for `bdlb::ScopeExit`.  But if
// our exit function has an unknown type (such as is the result of a `bind`
// expression) we are facing the same above two restrictions (see also
// {Example 3: Unknown Exit Function Type In C++03}).
//
// Given the C+03 restrictions, the following design decisions have been made:
// 1. Do not provide the utility and factory function when compiling with
//    C++03.
// 2. Provide a type `bdlb::ScopeExitAny` that is an alias to
//    `bdlb::ScopeExit<bsl::function<void()> >`.  An instance of
//    `bdlb::ScopeExitAny` can be created without having to name the type of
//    the exit function it is constructed from because `bsl::function`
//    provides type erasure.  The downside is the runtime performance cost of
//    type erasure (virtual function call that might inhibit inlining) and
//    potential memory allocation for stored arguments - all of which are the
//    cost of using `bsl::function`.
// 3. Provide `BDLB_SCOPEEXIT_PROCTOR` and `BDLB_SCOPEEXIT_GUARD` macros that
//    hide the difference between using a legacy C++03 `bdlb::ScopeExitAny`,
//    or C++ `auto` type deduction from the factory function call.  The macros
//    thereby will select the most efficient `bdlb::ScopeExit` type that is
//    feasible on the given compiler platform without having to specify the
//    exact type of the exit function (the template parameter to
//    `bdlb::ScopeExit`).
//
///Memory Allocation and Relationship with BDE Allocators
///------------------------------------------------------
// The exit function is created as a member of the guard object, so no memory
// is allocated for storing it.  However, if the exit function copy or move
// constructors require memory allocation, that memory is supplied by the
// currently installed default allocator.  Currently this component does not
// support custom allocators.  The main use-case of a guard object is to be
// created on the stack and automatic variables are supposed to use the
// default allocator, therefore no allocator support was added.
//
///Notes
///-----
// This component has been inspired by P0052R6 a since not-adopted ISO C++
// Library proposal, but has been extended to support C++03, BDE methodology,
// and attributes.
//
///Usage Examples
///--------------
// This section illustrates intended use of this component.
//
///Example 1: Using a Scope Exit Proctor in C++11 or later
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example we assume a C++ compiler supporting sufficiently functional
// C++11 or later.  Suppose we are creating a simple database that stores names
// and their associated addresses and we store the names and addresses in two
// separate tables.  While adding data, these tables may fail the insertion,
// in which case we need to roll back the already inserted data, such as if we
// inserted the address first, we need to remove it if insertion of the
// associated name fails.
//
// First, we emulate our database access with the following simple functions:
// ```
// int removedAddressId = 0;
// int insertAddress(const char *address)
// {
//     (void)address;
//     return (0 == removedAddressId ? 2 : 3);
// }
//
// int insertCustomer(const char *name, int addressId)
// {
//     (void)name;
//     (void)addressId;
//     if (0 == removedAddressId) throw 5; // Simulate failure once
//     return 7;
// }
//
// void removeAddress(int id)
// {
//     removedAddressId = id;
// }
// ```
// Next, we draw up our complex, customer-creating function signature:
// ```
// int addCustomer11(const char *name, const char *address)
// {
// ```
// Then we implement it, starting by inserting the address:
// ```
//     const int addressId = insertAddress(address);
// ```
// Our dummy function returns 42, indicating successful address insertion.
//
// Next, we create a proctor to remove the already inserted address if the name
// insertion fails:
// ```
//     auto addressProctor = bdlb::ScopeExitUtil::makeScopeExit(
//                                        [=](){ removeAddress(addressId); });
// ```
// Then, we attempt to insert the name:
// ```
//     const int custId = insertCustomer(name, addressId);
// ```
// As our dummy `insertCustomer` function will fail first time by throwing an
// exception (when `removedAddressId` is zero) we exit this function to the
// caller's error handling `catch` clause.  While exiting the function due to
// the exception, the local stack is unwound.  The non-trivial destructors of
// local variables are invoked (in the opposite order of their creation).  In
// this case, the destructor of `addressProctor` invokes its exit function,
// saving our non-zero `addressId` value into the global `removedAddressId`
// variable.
//
// On the second call to this function, because `removedAddressId` is now
// non-zero, `insertCustomer` will not fail, and we continue execution here.
//
// Next, if the insertion succeeded we are done, so we need to release the
// proctor to make the address permanent, after which we can return the ID:
// ```
//     addressProctor.release();
//
//     return custId;                                                // RETURN
// }
// ```
// Now we can verify that a first attempt to add a customer fails with the
// "right" exception and that `removedAddressId` is the expected value:
// ```
// bool seenException = false;
// try {
//     addCustomer11("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
// }
// catch (int exceptionValue) {
//     assert(5 == exceptionValue);
//     seenException = true;
// }
// assert(seenException);
// assert(2 == removedAddressId);
// ```
// Finally we verify that calling `addCustomer11` again succeeds with the right
// identifier returned, and that `removedAddressId` does not change:
// ```
// assert(7 == addCustomer11("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
// assert(2 == removedAddressId);
// ```
//
///Example 2: Using a Scope Exit Guard in C++03
/// - - - - - - - - - - - - - - - - - - - - - -
// Suppose we are in the same situation as in the C++11 or later example, but
// we have to create a solution that supports C++03 as well.
//
// First, we have to hand-craft a functor that calls `removeAddress` with a
// given ID because C++03 does not support lambdas:
// ```
// class RemoveAddress {
//     int d_id;  // the identifier of the address (row) to remove
//
//   public:
//     explicit RemoveAddress(int id)
//     : d_id(id)
//     {
//     }
//
//     void operator()() const
//     {
//         removeAddress(d_id);
//     }
// };
// ```
// Then, we implement the add customer function for C++03:
// ```
// int addCustomer03(const char *name, const char *address)
// {
//     const int addressId = insertAddress(address);
// ```
// The code is almost the same code as was in `addCustomer11` (the
// implementation that requires sufficiently functional C++11 or later
// platform), except for the proctor variable definition.
//
// Next, we define the proctor variable with an explicitly spelled out type
// (that uses the functor type template argument), and a functor object
// initialized with the identifier of the address to remove:
// ```
//     bdlb::ScopeExit<RemoveAddress> addrProctor((RemoveAddress(addressId)));
// ```
// Notice the extra parentheses we had to use to avoid "the most vexing parse"
// (https://en.wikipedia.org/wiki/Most_vexing_parse) issue.  Since we are in
// C++03, we cannot use (curly) brace initialization to avoid that issue.
//
// Now, we can complete the rest of the `addCustomer03`, which is exactly the
// same as the corresponding part of the `addCustomer11` variant:
// ```
//     const int custId = insertCustomer(name, addressId);
//     addrProctor.release();
//
//     return custId;                                                // RETURN
// }
// ```
// Finally, we can verify that both during the failing first attempt to add a
// customer to our imaginary database and the successful second attempt the
// `RemoveAddress` functor based proctor works just as well as the lambda based
// `addCustomer11` variant did:
// ```
// removedAddressId = 0;
// seenException = false;
// try {
//     addCustomer03("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
// }
// catch (int exceptionValue) {
//     assert(5 == exceptionValue);
//     seenException = true;
// }
// assert(seenException);
// assert(2 == removedAddressId);
//
// assert(7 == addCustomer03("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
// assert(2 == removedAddressId);
// ```
//
/// Example 3: Unknown Exit Function Type In C++03
///- - - - - - - - - - - - - - - - - - - - - - - -
// Suppose that we decide not to write a functor class for removing an address
// but use the function itself directly with `bdlf::BindUtil::bind` and that
// way keep the roll-back-code near the point of use like lambdas allow us in
// C++11 and later, albeit with a less elegant syntax.
//
// First, we design our bind expression as
// `bdlf::BindUtil::bind(&removeAddress, addressId)`.
//
// Then, we can even try it to see if it works as intended by calling the
// result of a bind expression using a constant for the address ID:
// ```
// removedAddressId = 0;
// bdlf::BindUtil::bind(&removeAddress, 11)();
// assert(11 == removedAddressId);
// ```
// Notice the subtle `()` after the bind expression.  We immediately call it
// after creating it (then destroy it).  We have to do it this way.  We have no
// idea what its type is so we cannot make a variable for it.
//
// Next, we create yet another customer adding function that differs only in
// its proctor definition from the `addCustomer11` variant:
// ```
// int addCustomerAny(const char *name, const char *address)
// {
//     const int addressId = insertAddress(address);
// ```
// Because we do not know the type of our exit function (it is "some functor
// object of some type", created by `bind`) we have to use the `bsl::function`
// based `bdlb::ScopeExitAny`:
// ```
//     bdlb::ScopeExitAny addressProctor(bdlf::BindUtil::bind(&removeAddress,
//                                                            addressId));
// ```
// Consult {C++03 Restrictions When Exit Function Type Is Unknown} to be aware
// what additional runtime costs this more compact code has compared to a
// "hand made" functor with a known type.
//
// Note that since we have to take the address of a function to create the
// `bind`-expression-functor we cannot use this format with standard library
// functions (unless taking their address is explicitly allowed by the C++
// standard), and if `removeAddress` were an overloaded function the code would
// not compile as the compiler would not know which address we want.
//
// The rest of the function is the same and omitted for brevity.
//
// Finally, we can verify that `bind` and `bdlb::ScopeExitAny` based proctor
// works just as well:
// ```
// removedAddressId = 0;
// seenException = false;
// try {
//     addCustomerAny("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
// }
// catch (int exceptionValue) {
//     assert(5 == exceptionValue);
//     seenException = true;
// }
// assert(seenException);
// assert(2 == removedAddressId);
//
// assert(7 == addCustomerAny("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
// assert(2 == removedAddressId);
// ```
//
///Example 4: Using the Scope Exit Proctor Macro
///- - - - - - - - - - - - - - - - - - - - - - -
// Suppose we have to create portable code that will compile with C++03 as well
// as C++11 and later compilers.  We also want our code to use the more
// efficient type-deducing `auto` with factory-method variant when compiled
// with a sufficiently functional C++11 or later compiler, and only fall back
// to the slower `bdlb::ScopeExitAny` solution on C++03 compilers.
//
// We still need to use either functor (`RemoveAddress` in our examples) or a
// bind expression for the exit function because C++03 has no lambdas,
// therefore our portable code cannot use lambdas.  But we *can* choose the
// easy-to-use `BDLB_SCOPEEXIT_PROCTOR` macro and not sprinkle the add customer
// function with `#ifdef` to see which proctor definition to use.
//
// To keep things simple this component provides a single proctor macro
// instead of two macro names to remember (one for the case case when the type
// of the exit function is known and one when it isn't).  In case the exit
// function name is known we can just directly use
// `bdlb::ScopeExit< --ExitFunctionType-- >` on any compiler.
//
// First, we start the add customer function as usual:
// ```
// int addCustomerMacro(const char *name, const char *address)
// {
//     const int addressId = insertAddress(address);
// ```
// Then, we define the proctor using a bind expression and the macro:
// ```
//     BDLB_SCOPEEXIT_PROCTOR(proctor, bdlf::BindUtil::bind(&removeAddress,
//                                                          addressId));
// ```
// Alternatively, we could have also written a functor and write the shorter
// `BDLB_SCOPEEXIT_PROCTOR(proctor, RemoveAddress(addressId))` for the proctor.
//
// The rest of the function is the same and omitted for brevity.
//
// Finally, we can verify the easy proctor with the now customary code:
// ```
// removedAddressId = 0;
// seenException = false;
// try {
//     addCustomerMacro("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
// }
// catch (int exceptionValue) {
//     assert(5 == exceptionValue);
//     seenException = true;
// }
// assert(seenException);
// assert(2 == removedAddressId);
//
// assert(7 == addCustomerMacro("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
// assert(2 == removedAddressId);
// ```
//
///Example 5: Using the Scope Exit Guard Macro
///- - - - - - - - - - - - - - - - - - - - - -
// Suppose that we are writing a printing system that is capable of printing
// out dynamic data structures that can contain numbers, strings, arrays, maps,
// etc.  When printing out data we often have to print delimiters and find
// that it is really easy to forget to print the closing the delimiter.  So we
// look for a simple way to automate them.  We decide we don't want to change
// the printing of the opening delimiters, just have a way to automate the
// printing of the close delimiters without worrying about early returns or
// `break`, `continue`, or other control flow changes.
//
// First, we create a functor type that prints closing delimiters:
// ```
// class CloseDelimPrinter {
//     const char *d_closingChars_p;  // held, not owned
//
//   public:
//     explicit CloseDelimPrinter(const char *s)
//     : d_closingChars_p(s)
//     {
//     }
//
//     void operator()() const
//     {
//         outStream << d_closingChars_p; // To a fixed stream for brevity
//     }
// };
// ```
// Then, we can use the above functor and a scope exit guard to automate
// closing of delimiters in the printing functions:
// ```
// void printTemplateWithArgs(
//                          const bsl::string_view>&             templateName,
//                          const bsl::vector<bsl::string_view>& args)
// {
// ```
// Next, we can move the printing of the opening delimiter and the closing one
// near each other in code, so it is clearly visible if an opened delimiter is
// closed:
// ```
//     outStream << templateName << '<';
//     BDLB_SCOPEEXIT_GUARD(CloseDelimPrinter(">"));
// ```
// The macro works in C++03 and C++11 and later, gives the guard variable a
// unique (but unspecified) name, adds an extra set of parentheses to take care
// of "the most vexing parse" and suppresses unused variable compiler warnings.
// The name for the guard variable created is unspecified.  Because this is a
// guard meaning we do not need to call `release()` (unlike a proctor),
// therefore the name is unimportant.
//
// Now, we can just print what goes inside the delimiters, and we are done:
// ```
//     if (args.empty()) {
//         // Safe to just return, the guard takes care of closing the '<'
//         return;                                                   // RETURN
//     }
//
//     typedef bsl::vector<bsl::string_view>::const_iterator Cit;
//
//     Cit cit = args.begin();
//     outStream << *cit;  // Print first argument
//     ++cit;
//
//     for (;cit != args.end(); ++cit) {
//         outStream << ", " << *cit;  // Print subsequent argument
//     }
//
//     const bsl::string_view last = *(args.end() - 1);
//     if (last.back() == '>') {
//         outStream << ' ';
//     }
// }
// ```
// Finally, we can print some templates and verify that the argument
// delimiters are closed:
// ```
// bsl::vector<bsl::string_view> targs;
// printTemplateWithArgs("TypeList", targs);
// assert(outStreamContent() == "TypeList<>");
//
// targs.push_back("bsl::string_view");
// printTemplateWithArgs("bsl::vector", targs);
// assert(outStreamContent() == "bsl::vector<bsl::string_view>");
//
// targs.push_back("bsl::vector<bsl::string_view>");
// printTemplateWithArgs("bsl::unordered_map", targs);
// assert(outStreamContent() ==
//    "bsl::unordered_map<bsl::string_view, bsl::vector<bsl::string_view> >");
// ```

#include <bdlscm_version.h>

#include <bsla_maybeunused.h>
#include <bsla_nodiscard.h>

#include <bslmf_assert.h>
#include <bslmf_conditional.h>
#include <bslmf_decay.h>
#include <bslmf_enableif.h>
#include <bslmf_isconvertible.h>
#include <bslmf_isfunction.h>
#include <bslmf_isnothrowmoveconstructible.h>
#include <bslmf_ispointer.h>
#include <bslmf_issame.h>
#include <bslmf_movableref.h>
#include <bslmf_removepointer.h>
#include <bslmf_util.h>

#include <bsl_functional.h>

#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
    #include <bsl_type_traits.h>
#endif
#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
    #include <bsl_utility.h>  // 'bsl::move'
#endif

#include <bsls_buildtarget.h>
#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_platform.h>
#include <bsls_util.h>

// ============================================================================
//                                 MACROS
// ============================================================================

#ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
    BSLMF_ASSERT(BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L);
        // 'BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L' is implied here.

    /// This macro determines if we have a sufficiently functional C++11 or
    /// later compiler so the type-deducing `auto` with factory-method can
    /// be compiled and works as expected.  When the macro is not defined
    /// (C++03 form) no utility `struct` (therefore no factory method) will
    /// be defined by this component and the variable definition macros (for
    /// Proctor and Guard) will use `bdlb::ScopeExitAny`.  When this macro
    /// is defined (C++11 or later that has sufficiently operation rvalue
    /// references and type-deducing `auto` keyword implementation) the
    /// factory method and its utility `struct` will be defined and the
    /// variable definition macros will use `auto` to determine the type of
    /// the `bdlb::ScopeExit` variable.  This macro is only internally in
    /// this component header and therefore it is undefined at the end of
    /// the file.
    #define BDLB_SCOPEEXIT_USES_MODERN_CPP
#endif

#ifdef BDE_BUILD_TARGET_EXC
    #define BDLB_SCOPEEXIT_NOEXCEPT_SPEC BSLS_KEYWORD_NOEXCEPT_SPECIFICATION
#else
    #define BDLB_SCOPEEXIT_NOEXCEPT_SPEC(...)
#endif
    // This macro is for internal use only and is undefined at the end of the
    // file.

/// Create a local variable with the specified `NAME` with a type that is an
/// instantiation of `bdlb::ScopeExit` initialized with the specified
/// `EXIT_FUNC`.  Note that the specific type of `bdlb::ScopeExit` used will
/// depend on available language features.
#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
    #define BDLB_SCOPEEXIT_PROCTOR(NAME, EXIT_FUNC) \
        auto NAME{ BloombergLP::bdlb::ScopeExitUtil::makeScopeExit(EXIT_FUNC) }
#else
    #define BDLB_SCOPEEXIT_PROCTOR(NAME, EXIT_FUNC) \
        BloombergLP::bdlb::ScopeExitAny NAME((EXIT_FUNC))
#endif


/// This macro is for use by `BDLB_SCOPEEXIT_GUARD` only to provide unique
/// variable names.  It is *not* undefined by the end of the file but its
/// direct use is not supported under any circumstances.
#define BDLB_SCOPEEXIT_PRIVATE_CAT(X, Y) BDLB_SCOPEEXIT_PRIVATE_CAT_IMP(X, Y)

/// This macro is for use by `BDLB_SCOPEEXIT_GUARD` only to provide unique
/// variable names.  It is *not* undefined by the end of the file but its
/// direct use is not supported under any circumstances.
#define BDLB_SCOPEEXIT_PRIVATE_CAT_IMP(X, Y) X##Y

/// This macro is for use by `BDLB_SCOPEEXIT_GUARD` only to provide unique
/// variable names.  It is *not* undefined by the end of the file but its
/// direct use is not supported under any circumstances.
#if defined(BSLS_PLATFORM_CMP_MSVC) || defined(BSLS_PLATFCORM_CMP_GNU) ||     \
    defined(BSLS_PLATFCORM_CMP_CLANG)
    // MSVC: The '__LINE__' macro breaks when '/ZI' is used (see Q199057 or
    // KB199057).  Fortunately the '__COUNTER__' extension provided by MSVC
    // is even better.  Since '__COUNTER__' is also available on all our
    // supported newer C++ platforms (GNU g++ and clang) we use it there as
    // well.
    #define BDLB_SCOPEEXIT_PRIVATE_UNIQNUM __COUNTER__
#else
    #define BDLB_SCOPEEXIT_PRIVATE_UNIQNUM __LINE__
#endif

/// Create a local variable with a generated unique name and with a type
/// that is an instantiation of `bdlb::ScopeExit` initialized with the
/// specified `EXIT_FUNC`.  Note that the specific type of `bdlb::ScopeExit`
/// used will depend on available language features.  The behavior is
/// undefined if this macro is used (expanded) more than once on the same
/// source line.  Note that using this macro in another macro more than once
/// is equivalent to using it more than once on the same source line.
#define BDLB_SCOPEEXIT_GUARD(EXIT_FUNC)                                       \
    BSLA_MAYBE_UNUSED                                                         \
    const BDLB_SCOPEEXIT_PROCTOR(                                             \
        BDLB_SCOPEEXIT_PRIVATE_CAT(bdlbScopeExitGuard_,                       \
                                   BDLB_SCOPEEXIT_PRIVATE_UNIQNUM),           \
                           EXIT_FUNC)

// ============================================================================
//                                CLASS TYPES
// ============================================================================

namespace BloombergLP {
namespace bdlb {

                             // ===============
                             // class ScopeExit
                             // ===============

/// `ScopeExit` is a general-purpose scope proctor class template that is
/// intended to be used as an automatic (stack) variable that calls an exit
/// function upon its destruction (when its scope is exited).
///
/// The template argument `EXIT_FUNC` shall be a function object type, or a
/// pointer to a function.  If `EXIT_FUNC` is an object type, it shall
/// satisfy the requirements of *Destructible*, *Callable*, and
/// *MoveConstructible* as specified by the ISO C++ standard.  Note that to
/// fulfill the *MoveConstructible* constraint a type does not have to
/// implement a move constructor.  If it has a copy constructor, that will
/// work fine as long at the move constructor is not deleted (or in case of
/// C++03 emulated moves, `private`).  The behavior is undefined if calling
/// (the member instance of) `EXIT_FUNC` throws an exception (as it will be
/// called from the destructor).
template <class EXIT_FUNC>
class BSLA_NODISCARD_CPP17 ScopeExit {

  private:
    // TEMPLATE PARAMETER CONTRACT
    BSLMF_ASSERT(
        !bsl::is_pointer<EXIT_FUNC>::value ||
        bsl::is_function<
                        typename bsl::remove_pointer<EXIT_FUNC>::type>::value);
        // Only function pointers are allowed, no other pointers.

    BSLMF_ASSERT(!bsl::is_reference<EXIT_FUNC>::value);
        // Reference types are not allowed, only objects.

    // We could check for more, but `is_destructible` needs full C++11
    // `<type_traits>` support, and `is_invocable` is C++17 or later.  So we
    // skip checking these to avoid major conditional compilation clutter.  The
    // chance of passing non-destructible or non-callable `EXIT_FUNC` argument
    // is low, and they will result in a reasonable error message.

  private:
    // PRIVATE TYPES

    /// Shorter lines for more readable code.
    typedef bslmf::MovableRefUtil MoveUtil;

  private:
    // PRIVATE DATA
    EXIT_FUNC d_exitFunction;          // A function pointer or functor to call
    bool      d_executeOnDestruction;  // `false` if `release` was called

  private:
    // NOT IMPLEMENTED
    ScopeExit(const ScopeExit&)            BSLS_KEYWORD_DELETED;  // No copying
    ScopeExit& operator=(const ScopeExit&) BSLS_KEYWORD_DELETED;  // No
#ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES            // assignment
    ScopeExit& operator=(ScopeExit&&)      BSLS_KEYWORD_DELETED;  // at all.
#endif

  public:
    // CREATORS

    /// Create a `ScopeExit` object, which, upon its destruction will invoke
    /// the specified `function` (or functor) unless its `release` method
    /// was called.  If `function` is copied into the `EXIT_FUNC` member,
    /// and that copy throws an exception, invoke `function` and rethrow the
    /// exception.  If `EXIT_FUNC_PARAM` cannot be move converted to
    /// `EXIT_FUNC` via no-throw means (either because such conversion does
    /// not exist or it is not marked as non-throwing), `function` will
    /// always be copied into the member.  This constructor participates in
    /// overload resolution only if `EXIT_FUNC_PARAM` is neither `EXIT_FUNC`
    /// nor `bdlb::ScopeExit<EXIT_FUNC>` and `EXIT_FUNC_PARAM` is
    /// convertible to `EXIT_FUNC`.  The behavior is undefined if `function`
    /// or the member instance of `EXIT_FUNC` throws an exception upon
    /// invocation.
    template <class EXIT_FUNC_PARAM>
    explicit ScopeExit(
        BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function,
#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
    // Enable explicit conversions on platforms where we can use
    // `bsl::is_constructible`.  Since this converting constructor itself is
    // marked `explicit` we are not enabling anything extra by allowing
    // `explicit` conversions when `EXIT_FUNC` is already explicitly
    // convertible.
        typename bsl::enable_if<
        bsl::is_constructible<  // Copy construct
            EXIT_FUNC,
            const typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type&
        >::value                                                             ||
        bsl::is_constructible<  // Move construct
            EXIT_FUNC,
            bslmf::MovableRef<typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type>
        >::value
                               >::type * = 0);
#else
    // `bsl::is_convertible` will not allow `explicit` conversions as we cannot
    // check their existence in C++03 without running into a compilation error.
        typename bsl::enable_if<
        bsl::is_convertible<  // "Copy convert"
            const typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type&,
            EXIT_FUNC
        >::value                                                             ||
        bsl::is_convertible<  // "Move convert"
            bslmf::MovableRef<typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type>,
            EXIT_FUNC
        >::value
                               >::type * = 0);
#endif

#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
    /// Create a `ScopeExit` object, which, upon its destruction will invoke
    /// the specified `function` unless the `release` method was called.
    /// If `function` is copied into the `EXIT_FUNC` member, and that copy
    /// throws an exception, invoke `function` and rethrow the exception.
    /// The behavior is undefined if `function` or the member instance of
    /// `EXIT_FUNC` throws an exception upon invocation.  Note that this
    /// separate constructor for function pointers exists because without it
    /// the forwarding logic in the templated constructor implementation
    /// generates warnings about meaningless types generated.
    explicit ScopeExit(void (*function)());
#endif

    /// If `bsl::is_nothrow_move_constructible<EXIT_FUNC>::value` is `true`
    /// or `EXIT_FUNC` is a move-only type, move construct, otherwise, copy
    /// construct the exit function from the specified `original`.  If
    /// construction succeeds, call `release()` on `original`.
    ScopeExit(bslmf::MovableRef<ScopeExit> original)
#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
        BDLB_SCOPEEXIT_NOEXCEPT_SPEC(
                         bsl::is_nothrow_move_constructible<EXIT_FUNC>::value
                      || bsl::is_nothrow_copy_constructible<EXIT_FUNC>::value);
#else
       BDLB_SCOPEEXIT_NOEXCEPT_SPEC(
                         bsl::is_nothrow_move_constructible<EXIT_FUNC>::value);
#endif

    /// Destroy this object.  Execute the exit function unless `release()`
    /// has been called on this object.
    ~ScopeExit();

  public:
    // MANIPULATORS

    /// Turn off the execution of the exit function of this object on
    /// destruction.
    void release();
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES
template <class EXIT_FUNC_PARAM>
explicit
ScopeExit(BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function) ->
                         ScopeExit<typename bsl::decay<EXIT_FUNC_PARAM>::type>;
#endif
                             // ====================
                             // typedef ScopeExitAny
                             // ====================

/// `ScopeExitAny` is an alias to `ScopeExit<bsl::function<void()> >`,
/// effectively making it a polymorphic scope exit type.
typedef ScopeExit<bsl::function<void()> > ScopeExitAny;

#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP

                             // ===================
                             // class ScopeExitUtil
                             // ===================

/// A utility that provides a factory function for sufficiently function
/// C++11 or later platforms to create scope guards using the type-deducing
/// `auto` keyword.  Notice that the utility type does not exist on C++03
/// platforms.
struct ScopeExitUtil {

    // CLASS METHODS

    /// Return a `ScopeExit` guard that uses the specified `function` as its
    /// exit function, and has the decayed type of `function` (class type or
    /// or function pointer type) as its exit function member type.
    template <class EXIT_FUNC_PARAM>
    BSLA_NODISCARD
    static
    ScopeExit<typename bsl::decay<EXIT_FUNC_PARAM>::type>
    makeScopeExit(EXIT_FUNC_PARAM&& function);
};
#endif // BDLB_SCOPEEXIT_USES_MODERN_CPP

// ============================================================================
//                           INLINE DEFINITIONS
// ============================================================================

                             // ---------------
                             // class ScopeExit
                             // ---------------

// CREATORS
template <class EXIT_FUNC>
template <class EXIT_FUNC_PARAM>
inline
ScopeExit<EXIT_FUNC>::ScopeExit(
    BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function,
    typename bsl::enable_if<
#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
        bsl::is_constructible<  // Copy construct
            EXIT_FUNC,
            const typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type&
        >::value                                                             ||
        bsl::is_constructible<  // Move construct
            EXIT_FUNC,
            bslmf::MovableRef<typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type>
        >::value
#else
        bsl::is_convertible<  // "Copy convert"
            const typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type&,
            EXIT_FUNC
        >::value                                                             ||
        bsl::is_convertible<  // "Move convert"
            bslmf::MovableRef<typename MoveUtil::Decay<EXIT_FUNC_PARAM>::type>,
            EXIT_FUNC
        >::value
#endif
                           >::type *)
#ifdef BDE_BUILD_TARGET_EXC
try
#endif
#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
: d_exitFunction(
    bslmf::Util::forward<
        typename bsl::conditional<
            bsl::is_nothrow_constructible<EXIT_FUNC,
                                            EXIT_FUNC_PARAM>::value ||
            !bsl::is_constructible<
                EXIT_FUNC,
                const typename MoveUtil::RemoveReference<
                                                    EXIT_FUNC_PARAM>::type&
            >::value,
            EXIT_FUNC_PARAM,
            const typename MoveUtil::RemoveReference<
                                                    EXIT_FUNC_PARAM>::type&
        >::type
    >(function))
#else  // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
: d_exitFunction(BSLS_COMPILERFEATURES_FORWARD(EXIT_FUNC_PARAM, function))
    // When we are unable to determine if it's safe to move the 'function'
    // parameter or not (based on its type, using type traits), we forward the
    // parameter in the usual manner, with the BDE-provided macro that picks
    // the best forwarding possible on the given compiler.  This prevents
    // compilation errors in case the functor is a move-only object.
#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
, d_executeOnDestruction(true)
{
}
#ifdef BDE_BUILD_TARGET_EXC
catch (...)
{
    MoveUtil::access(function)();
}
#endif

#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
template <class EXIT_FUNC>
inline ScopeExit<EXIT_FUNC>::ScopeExit(void (*function)())
#ifdef BDE_BUILD_TARGET_EXC
try
#endif
: d_exitFunction(function)
, d_executeOnDestruction(true)
{
}
#ifdef BDE_BUILD_TARGET_EXC
catch (...)
{
    function();
}
#endif
#endif  // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER

template <class EXIT_FUNC>
inline
ScopeExit<EXIT_FUNC>::ScopeExit(bslmf::MovableRef<ScopeExit> original)
#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
        BDLB_SCOPEEXIT_NOEXCEPT_SPEC(
                          bsl::is_nothrow_move_constructible<EXIT_FUNC>::value
                       || bsl::is_nothrow_copy_constructible<EXIT_FUNC>::value)
#else
       BDLB_SCOPEEXIT_NOEXCEPT_SPEC(
                          bsl::is_nothrow_move_constructible<EXIT_FUNC>::value)
#endif
: d_exitFunction(MoveUtil::move_if_noexcept(
                                    MoveUtil::access(original).d_exitFunction))
, d_executeOnDestruction(true)
{
    MoveUtil::access(original).release();
}

template <class EXIT_FUNC>
inline
ScopeExit<EXIT_FUNC>::~ScopeExit()
{
    if (d_executeOnDestruction) {
        d_exitFunction();
    }
}

// MANIPULATORS
template <class EXIT_FUNC>
inline
void ScopeExit<EXIT_FUNC>::release()
{
    d_executeOnDestruction = false;
}

#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP

                         // -------------------
                         // class ScopeExitUtil
                         // -------------------

// CLASS METHODS
template <class EXIT_FUNC_PARAM>
inline
ScopeExit<typename bsl::decay<EXIT_FUNC_PARAM>::type>
ScopeExitUtil::makeScopeExit(EXIT_FUNC_PARAM&& function)
{
    return ScopeExit<typename bsl::decay<EXIT_FUNC_PARAM>::type>(
                              bslmf::Util::forward<EXIT_FUNC_PARAM>(function));
}

#endif // BDLB_SCOPEEXIT_USES_MODERN_CPP

}  // close package namespace
}  // close enterprise namespace

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

#ifndef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
// In case there is no reliable '<type_traits>' header we use 'bsl' a trait to
// mark our class no-throw-move-constructible, if the single member is.

namespace bsl {
template <class EXIT_FUNC>
struct is_nothrow_move_constructible<BloombergLP::bdlb::ScopeExit<EXIT_FUNC> >
: is_nothrow_move_constructible<EXIT_FUNC>
{};
}  // close 'bsl' namespace
#endif

#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
#undef BDLB_SCOPEEXIT_USES_MODERN_CPP
#endif

#ifdef BDLB_SCOPEEXIT_NOEXCEPT_SPEC
#undef BDLB_SCOPEEXIT_NOEXCEPT_SPEC
#endif

#endif

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
